package cPanes;


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

import core.PShape;
import core.PaintThread;




import uiComponents.ContextMenu;
/**
 * DrawingPane provides basic graphics functionality. It supports drawing circles and rectangles (wireframe or filled) in a variety of
 * colors. It also emulates "pen" functionality by drawing a trail of small rectangles. The properties of every shape drawn are stored
 * as PShapes, which can theoretically be edited as a raster image. 
 */

public class DrawingPane extends CPane{
	private int paintType;
	private int paintW;
	private int paintH;
	private Color paintC;
	private ArrayList<PShape> draw;
	private PShape t;
	private String pmode;
	private JMenuItem pcolors[];
	private JMenuItem pshapes[];
	private JMenuItem pwidth[];
	private JMenuItem clear;
	private JMenuItem zoom[];
	private int tx=0;
	private int ty=0;
	
	/**
	 * The standard constructor. Sets the drawing pane up, adds to the context menu and initializes the array of shapes.
	 */
	public DrawingPane(){
		super();
		this.setName("DRAW");
		draw = new ArrayList();
		paintW=2;
		paintH=2;
		paintC = Color.BLACK;
		pmode="PEN";
		menu();
	}
	/**
	 * Instantiates the menu objects and adds them.
	 */
	private void menu(){
		ContextMenu m=this.getMenu();
		//Top-level menus
		JMenu zoomMenu = new JMenu("Zoom");
		JMenu pen = new JMenu("Pen Width");
		JMenu shapes = new JMenu("Drawing Mode");
		t= new PShape(paintC, 0, 0, 0, 0, "RECT");
		clear = new JMenuItem("Clear");
		clear.addActionListener(m);
		m.add(clear);
		//Zoom menu
		zoom = new JMenuItem[2];
		zoom[0]=new JMenuItem("Zoom In 25%");
		zoom[1]=new JMenuItem("Zoom Out 25%");
		zoomMenu.add(zoom[0]);
		zoomMenu.add(zoom[1]);
		m.add(zoomMenu);
		//Widths menu
		pwidth = new JMenuItem[6];
		for (int i=0; i< pwidth.length; i++){
			pwidth[i] = new JMenuItem(String.valueOf((i+1)));
			pwidth[i].addActionListener(m);
			pen.add(pwidth[i]);
		}
		//Shapes menu
		pshapes = new JMenuItem[7];
		pshapes[0] = new JMenuItem("Pen");
		pshapes[1] = new JMenuItem("Line");
		pshapes[2] = new JMenuItem("Rectangle");
		pshapes[3] = new JMenuItem("Oval");
		pshapes[4] = new JMenuItem("Filled Rectangle");
		pshapes[5] = new JMenuItem("Filled Oval");
		pshapes[6] = new JMenuItem("Erase");
		for (int i=0; i<pshapes.length; i++){
			shapes.add(pshapes[i]);
			pshapes[i].addActionListener(m);
		}
		m.add(pen);
		m.add(shapes);
		addColors();
	}
	/**
	 * Sets up the menu of pen colors. 
	 */
	private void addColors(){
		JMenu colors = new JMenu("Pen Color");
		pcolors=new JMenuItem[9];
		pcolors[0] = new JMenuItem("Blue");
		pcolors[1] = new JMenuItem("Orange");
		pcolors[2] = new JMenuItem("Green");
		pcolors[3] = new JMenuItem("Pink");
		pcolors[4] = new JMenuItem("White");
		pcolors[5] = new JMenuItem("Black");
		pcolors[6] = new JMenuItem("Red");
		pcolors[7] = new JMenuItem("Yellow");
		pcolors[8] = new JMenuItem("Gray");
		for (int i=0; i<pcolors.length; i++){
			pcolors[i].addActionListener(this.getMenu());
			colors.add(pcolors[i]);
		}
		this.getMenu().add(colors);
	}
	/**
	 * Handles menu events passed to this object by ContextMenu.
	 */
	public void menuActions(ActionEvent e) {
		Object t = e.getSource();
		//Change pen colors
		if (e.getSource().equals(pcolors[0])) paintC = Color.BLUE;
		else if (t.equals(pcolors[1])) paintC = Color.ORANGE;
		else if (t.equals(pcolors[2])) paintC = Color.GREEN;
		else if (t.equals(pcolors[3])) paintC = Color.PINK;
		else if (t.equals(pcolors[4])) paintC = Color.WHITE;
		else if (t.equals(pcolors[5])) paintC = Color.BLACK;
		else if (t.equals(pcolors[6])) paintC = Color.RED;
		else if (t.equals(pcolors[7])) paintC = Color.YELLOW;
		else if (t.equals(pcolors[8])) paintC = Color.GRAY;
		//Change drawing mode
		else if (t.equals(pshapes[0])) pmode = "PEN";
		else if (t.equals(pshapes[1])) pmode = "LINE";
		else if (t.equals(pshapes[2])) pmode = "RECT";
		else if (t.equals(pshapes[3])) pmode = "OVAL";
		else if (t.equals(pshapes[4])) pmode = "FRECT";
		else if (t.equals(pshapes[5])) pmode = "FOVAL";
		else if (t.equals(pshapes[6])) pmode = "ERASE";
		//Erase the screen
		else if (t.equals(clear)) {
			draw.clear();
			PaintThread q = new PaintThread(this);
			q.start();
		}
		else if (t.equals(zoom[0])){
			System.out.println("Zoom out");
			zoomPic(.75,.75);
			PaintThread q = new PaintThread(this);
			q.start();
		}
		else if (t.equals(zoom[1])){
			zoomPic(1.25,1.25);
			PaintThread q = new PaintThread(this);
			q.start();
		}
		//Change pen diameter 
		else{
			for (int i=0; i<5; i++){
				if (t.equals(pwidth[i])){
					paintW = 2*(i+1);
					paintH= 2*(i+1);
					break;
				}
			}
		}
	}
	/**
	 * Resizes the drawing pane, repaints the parent pane to avoid artifacts.
	 */
	void resizeContents(int owidth, int oheight) {
			scalePic((double)this.getWidth()/(double)owidth, (double)this.getHeight()/(double)oheight);
			PaintThread q = new PaintThread(this);
			q.start();
		//}
	}
	/**
	 * Resizes the picture on the canvas, without resizing the canvas
	 * @param scalew The amount by which to scale the width.
	 * @param scaleh The amount by which to scale the height.
	 */
	private void scalePic(double scalew, double scaleh){
		for (int i=0; i<draw.size(); i++){
			PShape t = draw.get(i);
			double x = t.getX();
			double y = t.getY();
			x = (x * scalew);
			y = (y * scaleh);
			t.setX(x);
			t.setY(y);
			double h = t.getHeight();
			double w = t.getWidth();
			w = (w * scalew);
			h = (h * scaleh);
			t.setHeight(h);
			t.setWidth(w);
		}
	}
	
	private void zoomPic(double scalew, double scaleh){
		for (int i=0; i<draw.size(); i++){
			PShape t = draw.get(i);
			double x = t.getX();
			double y = t.getY();
			double h = t.getHeight();
			double w = t.getWidth();
			w = (w * scalew);
			h = (h * scaleh);
			t.setHeight(h);
			t.setWidth(w);
			double fw = this.getWidth()/2;
			double fh = this.getHeight()/2;
			x = fw + (x-fw)*scalew;
			y = fh + (y-fh)*scaleh;
			t.setX(x);
			t.setY(y);
		}
	}
	
	/**
	 * Performs all the drawing functionality.
	 */
	void mouseActions(MouseEvent e, String type) {
		int mx = e.getX();
		int my = e.getY();
		if (type.equals("DRAGGED")){
			if (pmode.equals("PEN")){
				if (mx>0 && mx<this.getWidth() && my > 0 && my < this.getHeight()){
					PShape p = new PShape(paintC, mx, my, paintW, paintH, "FOVAL");
					draw.add(p);
					p.draw(this.getGraphics());
					if (Math.abs(mx-tx)>paintW && Math.abs(my-ty) > paintH) {
						p = new PShape(paintC, mx - (mx-tx)/2, my - (my-ty)/2, paintW, paintH, "FOVAL");
						draw.add(p);
						p.draw(this.getGraphics());
					}
					tx = mx;
					ty = my;
				}
			}
			else if (pmode.equals("ERASE")){
				for (int i=0; i<draw.size(); i++)
				{
					if (draw.get(i).contains(mx, my)) {
						draw.remove(i);
					}
				}
			}
			else if (pmode.equals("LINE")){
				t = new PShape(paintC, tx, ty, mx-tx, my-ty, pmode);
				t.draw(this.getGraphics());
			}
			else {
				int x,y,h,w;
				if (tx < mx) {
					x=tx;
					w=mx-tx;
				}
				else {
					x=mx;
					w=tx-x;
				}
				if (ty < my) {
					y=ty;
					h=my-ty;
				}
				else {
					y=my;
					h=ty-my;
				}
				t = new PShape(paintC, x, y, w, h, pmode);
				t.draw(this.getGraphics());
			}
			PaintThread q = new PaintThread(this);
			q.start();
		}
		else if (type.equals("PRESSED")){
			tx=mx;
			ty=my;
		}
		else if (type.equals("RELEASED")){
			int x,y,w,h;
			if (!pmode.equals("PEN")){
				if (pmode.equals("LINE")){
					PShape p = new PShape(paintC, tx, ty, mx-tx, my-ty, pmode);
					draw.add(p);
					p.draw(this.getGraphics());
					t=new PShape(paintC,0,0,0,0,"RECT");
				}
				else{
					if (tx < mx) {
						x=tx;
						w=mx-tx;
					}
					else {
						x=mx;
						w=tx-x;
					}
					if (ty < e.getY()) {
						y=ty;
						h=my-ty;
					}
					else {
						y=my;
						h=ty-my;
					}
					PShape p = new PShape(paintC, x, y, w, h, pmode);
					draw.add(p);
					p.draw(this.getGraphics());
					t=new PShape(paintC,0,0,0,0,"RECT");
				}
			}
		}
		else if (type.equals("CLICKED")){
			if (pmode.equals("ERASE")){
				for (int i=0; i<draw.size(); i++)
				{
					if (draw.get(i).contains(mx, my)) {
						draw.remove(i);
					}
				}
				PaintThread q = new PaintThread(this);
				q.start();
			}
		}
	}
	/**
	 * Splits the input string into lines - separated by '/' - and makes a new PShape from each.
	 */
	public void openSave(String s) {
		String[] p = s.split("/");
			for (int i=0; i<p.length; i++){
				PShape q = new PShape(p[i]);
				draw.add(q);
			}
			PaintThread q = new PaintThread(this);
			q.start();
	}
	/**
	 * Returns a String consisting of each PShape's properties, with each shape separated by '-'.
	 */
	public String returnSave() {
		String s="";
		for (int i=0; i<draw.size(); i++){
			s = s + draw.get(i).toString() + "/";
		}
		return s;
	}
	/**
	 * Overrides paintComponent, draws the PShapes from the array draw.
	 */
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		for (int i=0; i< draw.size(); i++){
			draw.get(i).draw(g);
		}
		t.draw(g);
	}

}
